package com.google.mediapipe.examples.facelandmarker

/*
 * Copyright 2023 The TensorFlow Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *             http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import android.R.attr.text
import android.content.Context
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.DashPathEffect
import android.graphics.Paint
import android.graphics.Path
import android.graphics.Point
import android.graphics.Rect
import android.util.AttributeSet
import android.util.Log
import android.view.View
import androidx.core.content.ContextCompat
import com.google.mediapipe.tasks.components.containers.NormalizedLandmark
import com.google.mediapipe.tasks.vision.core.RunningMode
import com.google.mediapipe.tasks.vision.facelandmarker.FaceLandmarkerResult
import kotlin.math.max
import kotlin.math.min


class OverlayView(context: Context?, attrs: AttributeSet?) :
    View(context, attrs) {

    private var results: FaceLandmarkerResult? = null
    private var linePaint = Paint()
    private var pointPaint = Paint()
    private var labelPaint = Paint()
    private var dotLinePaint = Paint()

    private var scaleFactor: Float = 1f
    private var imageWidth: Int = 1
    private var imageHeight: Int = 1
    private var mBitmap: android.graphics.Bitmap
    private var mBitMapTriangleUp: Bitmap
    private var mBitMapTriangleDown: Bitmap
    private var topX = 0f
    private var topY = 0f

    //初始化 eyes nose bottom left right 坐标
    private var eyesX = 0f
    private var eyesY = 0f
    private var noseX = 0f
    private var noseY = 0f
    private var bottomX = 0f
    private var bottomY = 0f
    private var rightX = 0f
    private var rightY = 0f
    private var leftX = 0f
    private var leftY = 0f
    private var screenWith = ScreenUtils.getScreenWidth(context!!)
    private var sceenHeight = ScreenUtils.getScreenHeight(context!!)
    private lateinit var myPath: Path;

    init {
        initPaints()
        mBitmap = BitmapFactory.decodeResource(resources, R.mipmap.ic_launcher);
        mBitMapTriangleUp = BitmapFactory.decodeResource(resources, R.mipmap.trangle_up);
        mBitMapTriangleDown = BitmapFactory.decodeResource(resources, R.mipmap.trangle_down);

    }

    fun clear() {
        results = null
        linePaint.reset()
        pointPaint.reset()
        labelPaint.reset()
        invalidate()
        initPaints()
    }

    private fun initPaints() {
        linePaint.color =
            ContextCompat.getColor(context!!, R.color.mp_color_primary)
        linePaint.strokeWidth = LANDMARK_STROKE_WIDTH
        linePaint.style = Paint.Style.STROKE

        pointPaint.color = Color.YELLOW
        pointPaint.strokeWidth = LANDMARK_STROKE_WIDTH
        pointPaint.style = Paint.Style.FILL

        labelPaint.color =
            ContextCompat.getColor(context!!, R.color.mp_color_primary)
        labelPaint.textSize = 28f
        labelPaint.strokeWidth = 4f
        labelPaint.style = Paint.Style.FILL
        labelPaint.isAntiAlias = true

        dotLinePaint = Paint()
        dotLinePaint.color = Color.WHITE
        dotLinePaint.strokeWidth = 5f
        dotLinePaint.style = Paint.Style.STROKE
        // 设置虚线效果，参数分别为：“点的间隔”，“点的长度”，“总的长度”
        dotLinePaint.setPathEffect(DashPathEffect(floatArrayOf(10f, 5f), 0f));
        myPath = Path()


    }

    fun initXY(landmarker: List<NormalizedLandmark>) {

        topX = landmarker[10].x() * imageWidth * scaleFactor
        topY = landmarker[10].y() * imageHeight * scaleFactor

        eyesX = landmarker[105].x() * imageWidth * scaleFactor
        eyesY = landmarker[105].y() * imageHeight * scaleFactor

        noseX = landmarker[19].x() * imageWidth * scaleFactor
        noseY = landmarker[19].y() * imageHeight * scaleFactor

        bottomX = landmarker[152].x() * imageWidth * scaleFactor
        bottomY = landmarker[152].y() * imageHeight * scaleFactor


        leftX = landmarker[162].x() * imageWidth * scaleFactor
        leftY = landmarker[162].y() * imageHeight * scaleFactor

        rightX = landmarker[389].x() * imageWidth * scaleFactor
        rightY = landmarker[389].y() * imageHeight * scaleFactor

        Log.d("overlay111111111", "leftX:$leftX,topY:$topY,rightX:$rightX,topY:$topY")
    }

    var list = arrayOf(
        10, 162, 389,
        70, 63, 105, 66, 107,
        336, 296, 334, 293, 300,
        19, 152
    )

    var startLine = 0;

    fun startAnimate() {

        if (startLine < 100) {
            startLine++
            invalidate()
        } else {

        }


    }

    override fun draw(canvas: Canvas) {
        super.draw(canvas)

        Log.d("draw", "draw")

        if (results == null || results!!.faceLandmarks().isEmpty()) {
            clear()
            return
        }

        results?.let { faceLandmarkerResult ->

            for (landmark in faceLandmarkerResult.faceLandmarks()) {
                Log.d("overlay", landmark.size.toString() + "")
                for ((index, normalizedLandmark) in landmark.withIndex()) {
                    if (list.indexOf(index) > -1) {
//                        canvas.drawPoint(normalizedLandmark.x() * imageWidth * scaleFactor, normalizedLandmark.y() * imageHeight * scaleFactor, pointPaint)
                    }
//                    canvas.drawPoint(normalizedLandmark.x() * imageWidth * scaleFactor, normalizedLandmark.y() * imageHeight * scaleFactor, pointPaint)
                }

                initXY(landmark)


            }

//            FaceLandmarker.FACE_LANDMARKS_CONNECTORS.forEach {
//                canvas.drawLine(
//                    faceLandmarkerResult.faceLandmarks().get(0).get(it!!.start()).x() * imageWidth * scaleFactor,
//                    faceLandmarkerResult.faceLandmarks().get(0).get(it.start()).y() * imageHeight * scaleFactor,
//                    faceLandmarkerResult.faceLandmarks().get(0).get(it.end()).x() * imageWidth * scaleFactor,
//                    faceLandmarkerResult.faceLandmarks().get(0).get(it.end()).y() * imageHeight * scaleFactor,
//                    linePaint)
//            }


            canvas.save()
            // 设置文字垂直居中
            labelPaint.setTextAlign(Paint.Align.CENTER)
            labelPaint.color = Color.WHITE
            // 获取文字的宽度
            val textWidth: Float = labelPaint.measureText("中庭高度")
            // 设置Canvas的坐标轴，使得文字竖直排列
            //上庭长度  leftX + (topX - leftX) * 0.6 topY


            canvas.rotate(90f, (leftX + (topX - leftX) * 0.6).toFloat(), topY)
            // 将文字移动到垂直居中的位置
            canvas.drawText("上庭长度", ((leftX + (topX - leftX) * 0.6 + textWidth / 2).toFloat()), topY, labelPaint)

            labelPaint.color = ContextCompat.getColor(context!!, R.color.mp_color_primary)
            labelPaint.textSize = 32f
            canvas.drawText("10.00mm", ((leftX + (topX - leftX) * 0.6 + textWidth / 2).toFloat()), topY + 40, labelPaint)

            canvas.restore()

            //中庭长度 leftX eyesY
            canvas.save()
            canvas.rotate(90f, (leftX), eyesY)
            // 将文字移动到垂直居中的位置
            labelPaint.color = Color.WHITE
            labelPaint.textSize = 28f
            canvas.drawText("中庭长度", (leftX) + (noseY - eyesY) / 2, eyesY, labelPaint)

            labelPaint.color = ContextCompat.getColor(context!!, R.color.mp_color_primary)
            labelPaint.textSize = 32f
            canvas.drawText("10.00mm", (leftX) + (noseY - eyesY) / 2, eyesY + 40, labelPaint)
            canvas.restore()
            canvas.save()

            //下庭长度
            canvas.rotate(90f, (rightX - (rightX - noseX) * 0.3).toFloat(), noseY)
            // 将文字移动到垂直居中的位置
            labelPaint.color = Color.WHITE
            labelPaint.textSize = 28f
            canvas.drawText("下庭长度", (rightX - (rightX - noseX) * 0.3 + (bottomY - noseY) / 2).toFloat(), noseY, labelPaint)

            labelPaint.color = ContextCompat.getColor(context!!, R.color.mp_color_primary)
            labelPaint.textSize = 32f
            canvas.drawText("10.00mm", (rightX - (rightX - noseX) * 0.3 + (bottomY - noseY) / 2).toFloat(), noseY + 40, labelPaint)
            canvas.restore()


            canvas.drawPoint(leftX, leftY, pointPaint)

            // 画出原图像
            canvas.drawBitmap(mBitmap, 80f, 180f, labelPaint);
            val src = Rect(0, 0, mBitmap.width / 2, mBitmap.height / 2);
            val dstTop = Rect((leftX).toInt() - 100, (topY).toInt(), (rightX).toInt(), (topY).toInt() + 4);
            canvas.drawBitmap(mBitmap, src, dstTop, null);

            val dstM1 = Rect((leftX).toInt() - 100, (eyesY).toInt(), (rightX).toInt(), (eyesY).toInt() + 4);
            canvas.drawBitmap(mBitmap, src, dstM1, null);


            val dstM2 = Rect((leftX).toInt() - 100, (noseY).toInt(), (rightX).toInt(), (noseY).toInt() + 4);
            canvas.drawBitmap(mBitmap, src, dstM2, null)

            val dstBottom = Rect((leftX).toInt() - 100, (bottomY).toInt(), (rightX).toInt(), (bottomY).toInt() + 4);
            canvas.drawBitmap(mBitmap, src, dstBottom, null);

            myPath.reset();
            myPath.moveTo(topX, topY);
            myPath.lineTo(topX + (bottomX - topX) * startLine / 100, topY + (bottomY - topY) * startLine / 100);
            try {
                startAnimate()
            } catch (e: Exception) {


            }


            // 绘制虚线
            canvas.drawPath(myPath, dotLinePaint);
            //绘制label 三角形 上箭头
            val srcTriangleUp = Rect(0, 0, mBitMapTriangleUp.width, mBitMapTriangleUp.height);
            val srcTriangleDown = Rect(0, 0, mBitMapTriangleDown.width, mBitMapTriangleDown.height);
            val dstTopUp = Rect((leftX + (topX - leftX) * 0.6).toInt(), (topY).toInt(), ((leftX + (topX - leftX) * 0.6) + mBitMapTriangleUp.width).toInt(), (topY + mBitMapTriangleUp.height).toInt());
            canvas.drawBitmap(mBitMapTriangleUp, srcTriangleUp, dstTopUp, null);

            val dstTopDown = Rect((leftX + (topX - leftX) * 0.6).toInt(), (eyesY).toInt() - mBitMapTriangleDown.height, ((leftX + (topX - leftX) * 0.6) + mBitMapTriangleDown.width).toInt(), (eyesY).toInt());
            canvas.drawBitmap(mBitMapTriangleDown, srcTriangleDown, dstTopDown, null);

            myPath.reset();
            myPath.moveTo(((leftX + (topX - leftX) * 0.6 + mBitMapTriangleUp.width / 2).toFloat()), topY + mBitMapTriangleUp.height / 2);
            myPath.lineTo(((leftX + (topX - leftX) * 0.6 + mBitMapTriangleUp.width / 2).toFloat()), eyesY - mBitMapTriangleUp.height / 2);
            canvas.drawPath(myPath, dotLinePaint);


            val dstEyesUp = Rect((leftX).toInt(), (eyesY).toInt(), ((leftX) + mBitMapTriangleUp.width).toInt(), (eyesY + mBitMapTriangleUp.height).toInt());
            canvas.drawBitmap(mBitMapTriangleUp, srcTriangleUp, dstEyesUp, null);

            val dstEyesDown = Rect((leftX).toInt(), (noseY).toInt() - mBitMapTriangleDown.height, ((leftX) + mBitMapTriangleDown.width).toInt(), (noseY).toInt());
            canvas.drawBitmap(mBitMapTriangleDown, srcTriangleDown, dstEyesDown, null);

            myPath.reset();
            myPath.moveTo(((leftX + mBitMapTriangleUp.width / 2)), eyesY + mBitMapTriangleUp.height / 2);
            myPath.lineTo(((leftX + mBitMapTriangleUp.width / 2)), mBitMapTriangleUp.height / 2 + (eyesY + noseY) / 2 - textWidth / 2);
            myPath.moveTo(((leftX + mBitMapTriangleUp.width / 2)), mBitMapTriangleUp.height / 2 + (eyesY + noseY) / 2 + textWidth / 2);
            myPath.lineTo(((leftX + mBitMapTriangleUp.width / 2)), noseY - mBitMapTriangleUp.height / 2);
            canvas.drawPath(myPath, dotLinePaint);


            val dstNoseUp = Rect((rightX - (rightX - noseX) * 0.3).toInt(), (noseY).toInt(), ((rightX - (rightX - noseX) * 0.3) + mBitMapTriangleUp.width).toInt(), (noseY + mBitMapTriangleUp.height).toInt());
            canvas.drawBitmap(mBitMapTriangleUp, srcTriangleUp, dstNoseUp, null);

            val dstNosedown = Rect((rightX - (rightX - noseX) * 0.3).toInt(), (bottomY - mBitMapTriangleDown.height).toInt(), ((rightX - (rightX - noseX) * 0.3) + mBitMapTriangleDown.width).toInt(), (bottomY).toInt());
            canvas.drawBitmap(mBitMapTriangleDown, srcTriangleDown, dstNosedown, null);

            myPath.reset();
            myPath.moveTo(((rightX - (rightX - noseX) * 0.3) + mBitMapTriangleUp.width / 2).toFloat(), noseY + mBitMapTriangleUp.height / 2);
            myPath.lineTo(((rightX - (rightX - noseX) * 0.3) + mBitMapTriangleUp.width / 2).toFloat(), mBitMapTriangleUp.height / 2 + (bottomY + noseY) / 2 - textWidth / 2);
            myPath.moveTo(((rightX - (rightX - noseX) * 0.3) + mBitMapTriangleUp.width / 2).toFloat(), mBitMapTriangleUp.height / 2 + (bottomY + noseY) / 2 + textWidth / 2);
            myPath.lineTo(((rightX - (rightX - noseX) * 0.3) + mBitMapTriangleUp.width / 2).toFloat(), bottomY - mBitMapTriangleUp.height / 2);
            canvas.drawPath(myPath, dotLinePaint);

        }
    }

    fun setResults(
        faceLandmarkerResults: FaceLandmarkerResult,
        imageHeight: Int,
        imageWidth: Int,
        runningMode: RunningMode = RunningMode.IMAGE
    ) {
        results = faceLandmarkerResults

        this.imageHeight = imageHeight
        this.imageWidth = imageWidth

        scaleFactor = when (runningMode) {
            RunningMode.IMAGE,
            RunningMode.VIDEO -> {
                min(width * 1f / imageWidth, height * 1f / imageHeight)
            }

            RunningMode.LIVE_STREAM -> {
                // PreviewView is in FILL_START mode. So we need to scale up the
                // landmarks to match with the size that the captured images will be
                // displayed.
                max(width * 1f / imageWidth, height * 1f / imageHeight)
            }
        }
        invalidate()
    }

    companion object {
        private const val LANDMARK_STROKE_WIDTH = 8F
        private const val TAG = "Face Landmarker Overlay"
    }

    //    x=(x1-x2)cosθ-(y1-y2)sinθ+x2
//    y=(y1-y2)cosθ+(x1-x2)sinθ+y2
    fun rotatePoint(point: Point, center: Point): Point {
        var result: Point = Point()
        result.x = center.y - point.y + center.x
        result.y = point.x - center.x + center.y

        return result

    }
}
